# Configure Rspack

Rsbuild supports directly modifying the Rspack configuration object, and supports modifying the built-in Rspack configuration of Rsbuild through `rspack-chain`.

:::tip
The built-in Rspack config in Rsbuild may change with iterations, and these changes will not be reflected in semver. Therefore, your custom config may become invalid when you upgrade Rsbuild.
:::

## View Rspack config

Rsbuild provides the [rsbuild inspect](/guide/basic/cli#rsbuild-inspect) command to view the final Rspack config generated by Rsbuild.

You can also view it through [debug mode](/guide/debug/debug-mode).

## Modify config object

You can use the [tools.rspack](/config/tools/rspack) option of Rsbuild to modify the Rspack config object.

For example, registering a built-in Rspack plugin:

```ts title="rsbuild.config.ts"
import { rspack } from '@rsbuild/core';

export default {
  tools: {
    rspack: {
      plugins: [
        new rspack.CircularDependencyRspackPlugin({
          // options
        }),
      ],
    },
  },
};
```

Or registering a community webpack plugin:

```ts title="rsbuild.config.ts"
import { sentryWebpackPlugin } from '@sentry/webpack-plugin';

export default {
  tools: {
    rspack: {
      plugins: [
        sentryWebpackPlugin({
          // options
        }),
      ],
    },
  },
};
```

Or modify the built-in Rspack config with a function:

```ts title="rsbuild.config.ts"
export default {
  tools: {
    rspack: (config, { env }) => {
      if (env === 'development') {
        config.devtool = 'cheap-module-eval-source-map';
      }
      return config;
    },
  },
};
```

> Please refer to the [tools.rspack documentation](/config/tools/rspack) for detailed usage.

## Access Rspack API

If you need to access the API or plugins exported by [@rspack/core](https://npmjs.com/package/@rspack/core), you can directly import the [rspack](/api/javascript-api/core#rspack) object from `@rsbuild/core` without installing the `@rspack/core` package separately.

```ts title="rsbuild.config.ts"
import { rspack } from '@rsbuild/core';

export default {
  tools: {
    rspack: {
      plugins: [
        new rspack.BannerPlugin({
          // ...
        }),
      ],
    },
  },
};
```

:::tip

- Refer to [Rspack plugins](https://rspack.rs/plugins/) and [Rspack JavaScript API](https://rspack.rs/api/javascript-api/) to learn more about the available Rspack APIs.
- It's not recommended to manually install the `@rspack/core` package, as it may conflict with the version that Rsbuild depends on.

:::

## Use bundler chain

import RspackChain from '@en/shared/rspackChain.mdx';

<RspackChain />

### tools.bundlerChain

Rsbuild provides the [tools.bundlerChain](/config/tools/bundler-chain) config to modify the rspack-chain. Its value is a function that takes two arguments:

- The first argument is an `rspack-chain` instance, which you can use to modify the Rspack config.
- The second argument is an utils object, including `env`, `isProd`, `CHAIN_ID`, etc.

Here is a basic example:

```ts title="rsbuild.config.ts"
export default {
  tools: {
    bundlerChain: (chain, { env }) => {
      if (env === 'development') {
        chain.devtool('cheap-module-eval-source-map');
      }
    },
  },
};
```

`tools.bundlerChain` can also be an async function:

```ts title="rsbuild.config.ts"
export default {
  tools: {
    bundlerChain: (chain, { env }) => {
      const value = await fetchValue();
      chain.devtool(value);
    },
  },
};
```

### Basics

Before using the rspack-chain to modify the Rspack configuration, it is recommended to familiarize yourself with some basics.

#### About ID

In short, the rspack-chain requires users to set a unique ID for each rule, loader, plugin, and minimizer. With this ID, you can easily find the desired object from deeply nested objects.

Rsbuild exports all internally defined IDs through the `CHAIN_ID` object, so you can quickly locate the loader or plugin you want to modify using these exported IDs, without the need for complex traversal in the Rspack configuration object.

For example, you can remove the built-in CSS rule using `CHAIN_ID.RULE.CSS`:

```ts title="rsbuild.config.ts"
export default {
  tools: {
    bundlerChain: (chain, { CHAIN_ID }) => {
      chain.module.rules.delete(CHAIN_ID.RULE.CSS);
    },
  },
};
```

#### ID types

The `CHAIN_ID` object contains various IDs, which correspond to the following configurations:

| CHAIN_ID Field       | Corresponding Configuration | Description                                            |
| -------------------- | --------------------------- | ------------------------------------------------------ |
| `CHAIN_ID.PLUGIN`    | `plugins[i]`                | Corresponds to a plugin in the Rspack configuration    |
| `CHAIN_ID.RULE`      | `module.rules[i]`           | Corresponds to a rule in the Rspack configuration      |
| `CHAIN_ID.USE`       | `module.rules[i].loader`    | Corresponds to a loader in the Rspack configuration    |
| `CHAIN_ID.MINIMIZER` | `optimization.minimizer`    | Corresponds to a minimizer in the Rspack configuration |

### Examples

#### Custom loader

Here are examples of adding, modifying, and removing Rspack loaders.

- Add a loader to handle `.md` files:

```js title="rsbuild.config.mjs"
export default {
  tools: {
    bundlerChain: (chain) => {
      chain.module
        .rule('md')
        .test(/\.md$/)
        .use('md-loader')
        // The package name or module path of the loader
        .loader('md-loader');
    },
  },
};
```

- Modify options of the built-in SWC loader:

```js title="rsbuild.config.mjs"
export default {
  tools: {
    bundlerChain: (chain, { CHAIN_ID }) => {
      chain.module
        .rule(CHAIN_ID.RULE.JS)
        .use(CHAIN_ID.USE.SWC)
        .tap((options) => {
          console.log(options);
          return options;
        });
    },
  },
};
```

- Remove the built-in SWC loader:

```js title="rsbuild.config.mjs"
export default {
  tools: {
    bundlerChain: (chain, { CHAIN_ID }) => {
      chain.module.rule(CHAIN_ID.RULE.JS).uses.delete(CHAIN_ID.USE.SWC);
    },
  },
};
```

- Insert a loader after the built-in SWC loader that executes earlier:

```js title="rsbuild.config.mjs"
export default {
  tools: {
    bundlerChain: (chain, { CHAIN_ID }) => {
      chain.module
        .rule(CHAIN_ID.RULE.JS)
        .use('my-loader')
        .after(CHAIN_ID.USE.SWC)
        // The package name or module path of the loader
        .loader('my-loader')
        .options({
          // some options
        });
    },
  },
};
```

> Note: Rspack loaders are executed in reverse order.

- Insert a loader before the built-in SWC loader that executes later:

```js title="rsbuild.config.mjs"
export default {
  tools: {
    bundlerChain: (chain, { CHAIN_ID }) => {
      chain.module
        .rule(CHAIN_ID.RULE.JS)
        // Loader ID, not actually meaningful, just for locating
        .use('my-loader')
        .before(CHAIN_ID.USE.SWC)
        // The package name or module path of the loader
        .loader('my-loader')
        .options({
          // some options
        });
    },
  },
};
```

- Remove the built-in CSS handling rule:

```js title="rsbuild.config.mjs"
export default {
  tools: {
    bundlerChain: (chain, { CHAIN_ID }) => {
      chain.module.rules.delete(CHAIN_ID.RULE.CSS);
    },
  },
};
```

#### Custom plugin

Here are examples of adding, modifying, and deleting Rspack plugins.

```js title="rsbuild.config.mjs"
export default {
  tools: {
    bundlerChain: (chain, { bundler, CHAIN_ID }) => {
      // Add plugin
      chain.plugin('custom-define').use(bundler.DefinePlugin, [
        {
          'process.env': {
            NODE_ENV: JSON.stringify(process.env.NODE_ENV),
          },
        },
      ]);

      // Modify plugin
      chain.plugin(CHAIN_ID.PLUGIN.HMR).tap((options) => {
        options[0].fullBuildTimeout = 200;
        return options;
      });

      // Delete plugin
      chain.plugins.delete(CHAIN_ID.PLUGIN.HMR);
    },
  },
};
```

:::tip
In most cases, you should change the plugin options using the configurations provided by Rsbuild, rather than using `CHAIN_ID.PLUGIN`, as this may lead to unexpected behavior.

For example, use [tools.htmlPlugin](/config/tools/html-plugin) to change the options of HtmlPlugin.
:::

#### Modify based on environment

In the `tools.bundlerChain` function, you can access various environment identifiers in the second parameter, such as development/production build, SSR build, Web Worker build, to achieve configuration modifications for different environments.

```js title="rsbuild.config.mjs"
export default {
  tools: {
    bundlerChain: (chain, { env, isProd, target, isServer, isWebWorker }) => {
      if (env === 'development' || env === 'test') {
        // ...
      }
      if (isProd) {
        // ...
      }
      if (target === 'node') {
        // ...
      }
      if (isServer) {
        // ...
      }
      if (isWebWorker) {
        // ...
      }
    },
};
```

The above are some common configuration examples. For the complete rspack-chain API, please refer to the [rspack-chain documentation](https://github.com/rspack-contrib/rspack-chain).

## Configuration modification order

Rsbuild supports modifying the Rspack configuration object through `tools.rspack`, `tools.bundlerChain`, `modifyBundlerChain`, etc.

The order of execution between them is:

- [modifyBundlerChain](/plugins/dev/hooks#modifybundlerchain)
- [tools.bundleChain](/config/tools/bundler-chain)
- [modifyRspackConfig](/plugins/dev/hooks#modifyrspackconfig)
- [tools.rspack](/config/tools/rspack)
